<template>
  <Teleport
    v-if="enableGmailTools"
    :to="rootElement"
  >
    <ShadowRootComponent ref="shadowRootRef">
      <div
        ref="containerRef"
        class="nativemind-gmail-tools nativemind-style-boundary"
        :style="{'all': 'initial', position: 'fixed', top: '0', left: '0', width: '0px', height: '0px'}"
      >
        <div
          class="container bg-bg-primary text-text-primary font-inter"
          :data-nm-theme="currentTheme"
        >
          <div
            v-if="showReplyCard"
            ref="popupRef"
            class="popup bg-bg-primary fixed rounded-md z-50 shadow-[0px_8px_16px_0px_var(--color-shadow-medium),0px_4px_8px_0px_var(--color-shadow-medium),0px_0px_0px_1px_var(--color-shadow-medium)]"
            :class="!popupPos ? 'opacity-0' : ''"
            :style="popupPos ? { top: popupPos.top + 'px', left: popupPos.left + 'px' } : {}"
          >
            <GmailReplyCard
              :clickedButtonElement="clickedReplyButtonRef"
              @close="onCloseReplyCard"
              @apply="onApplyReply"
            />
          </div>
          <div
            v-if="showComposeCard"
            ref="composePopupRef"
            class="popup bg-bg-primary fixed rounded-md z-50 shadow-[0px_8px_16px_0px_var(--color-shadow-medium),0px_4px_8px_0px_var(--color-shadow-medium),0px_0px_0px_1px_var(--color-shadow-medium)]"
            :class="!composePopupPos ? 'opacity-0' : ''"
            :style="composePopupPos ? { top: composePopupPos.top + 'px', left: composePopupPos.left + 'px' } : {}"
          >
            <GmailComposeCard
              :clickedButtonElement="clickedComposeButtonRef"
              @close="onCloseComposeCard"
              @apply="onApplyCompose"
            />
          </div>
        </div>
      </div>
    </ShadowRootComponent>
  </Teleport>
</template>

<script setup lang="ts">
import { useElementBounding } from '@vueuse/core'
import { computed, onMounted, ref, shallowRef, watchEffect } from 'vue'
import { ShadowRoot as ShadowRootComponent } from 'vue-shadow-dom'

import { useTheme } from '@/composables/theme'
import { useDraggable } from '@/composables/useDraggable'
import { useLogger } from '@/composables/useLogger'
import { injectStyleSheetToDocument, loadContentScriptStyleSheet } from '@/utils/css'
import { getUserConfig } from '@/utils/user-config'

import { useRootElement } from '../../composables/useRootElement'
import GmailComposeCard from './GmailComposeCard.vue'
import GmailReplyCard from './GmailReplyCard.vue'

const logger = useLogger()
const rootElement = useRootElement()
const styleSheet = shallowRef<CSSStyleSheet | null>(null)
const shadowRootRef = ref<InstanceType<typeof ShadowRoot>>()
const containerRef = ref<HTMLDivElement>()

// Initialize theme
const { initializeTheme, currentTheme } = useTheme()
initializeTheme()
const popupRef = ref<HTMLDivElement | null>(null)
const composePopupRef = ref<HTMLDivElement | null>(null)
const clickedReplyButtonRef = ref<HTMLElement | null>(null) // for navigating current polish button and finding its parent compose dialog
const clickedComposeButtonRef = ref<HTMLElement | null>(null) // for navigating current compose button and finding its parent compose dialog

// Drag handles for popup title bars
const replyDragHandleRef = ref<HTMLElement | null>(null)
const composeDragHandleRef = ref<HTMLElement | null>(null)

const userConfig = await getUserConfig()
const enabled = userConfig.emailTools.enable.toRef()

const enableGmailTools = computed(() => {
  return enabled.value
})

// Reply card state
const showReplyCard = ref(false)
const replyButtonElement = ref<HTMLElement | null>(null)
const popupBounding = useElementBounding(popupRef)

// Compose card state
const showComposeCard = ref(false)
const composeButtonElement = ref<HTMLElement | null>(null)
const composePopupBounding = useElementBounding(composePopupRef)

// Initialize draggable functionality for both popups
const replyDraggable = useDraggable(popupRef, {
  handle: replyDragHandleRef,
})

const composeDraggable = useDraggable(composePopupRef, {
  handle: composeDragHandleRef,
})

const popupPos = computed(() => {
  if (!replyButtonElement.value || popupBounding.height.value === 0 || popupBounding.width.value === 0) {
    return null
  }

  const buttonRect = replyButtonElement.value.getBoundingClientRect()
  const gap = 4 // px
  let top = buttonRect.top - popupBounding.height.value - gap
  let left = buttonRect.left // 左对齐

  // Prevent popup from going out of viewport
  if (top < 0) {
    top = buttonRect.bottom + gap
  }
  if (left < 0) {
    left = 0
  }
  if (left + popupBounding.width.value > window.innerWidth) {
    left = window.innerWidth - popupBounding.width.value
  }
  if (top + popupBounding.height.value > window.innerHeight) {
    top = window.innerHeight - popupBounding.height.value
  }

  return { top, left }
})

const composePopupPos = computed(() => {
  if (!composeButtonElement.value || composePopupBounding.height.value === 0 || composePopupBounding.width.value === 0) {
    return null
  }

  const buttonRect = composeButtonElement.value.getBoundingClientRect()
  const gap = 4 // px
  let top = buttonRect.top - composePopupBounding.height.value - gap
  let left = buttonRect.left // 左对齐

  // Prevent popup from going out of viewport
  if (top < 0) {
    top = buttonRect.bottom + gap
  }
  if (left < 0) {
    left = 0
  }
  if (left + composePopupBounding.width.value > window.innerWidth) {
    left = window.innerWidth - composePopupBounding.width.value
  }
  if (top + composePopupBounding.height.value > window.innerHeight) {
    top = window.innerHeight - composePopupBounding.height.value
  }

  return { top, left }
})

const onShowReplyCard = (buttonElement: HTMLElement, clickedButtonElement: HTMLElement) => {
  replyButtonElement.value = buttonElement
  clickedReplyButtonRef.value = clickedButtonElement
  showReplyCard.value = true

  // Initialize dragging after popup is shown
  setTimeout(() => {
    if (popupRef.value) {
      replyDragHandleRef.value = popupRef.value.querySelector('.title') as HTMLElement
      replyDraggable.initDraggable()
    }
  }, 0)
}

const onCloseReplyCard = () => {
  showReplyCard.value = false
  replyButtonElement.value = null
  replyDraggable.resetPosition()
}

const onApplyReply = (text: string) => {
  // TODO: Apply the reply text to the compose field
  logger.debug('Apply reply:', text)
  onCloseReplyCard()
}

const onShowComposeCard = (buttonElement: HTMLElement, clickedButtonElement: HTMLElement) => {
  composeButtonElement.value = buttonElement
  clickedComposeButtonRef.value = clickedButtonElement
  showComposeCard.value = true

  // Initialize dragging after popup is shown
  setTimeout(() => {
    if (composePopupRef.value) {
      composeDragHandleRef.value = composePopupRef.value.querySelector('.title') as HTMLElement
      composeDraggable.initDraggable()
    }
  }, 0)
}

const onCloseComposeCard = () => {
  showComposeCard.value = false
  composeButtonElement.value = null
  composeDraggable.resetPosition()
}

const onApplyCompose = (data: { subject: string, body: string }) => {
  logger.debug('Apply compose:', data)
  onCloseComposeCard()
}

// Listen for custom events from page injection
document.addEventListener('nativemind:show-reply-card', ((event: CustomEvent) => {
  const { buttonData } = event.detail

  const element = buttonData.el as HTMLElement

  // Create a virtual element with the button position data
  const virtualButton = {
    getBoundingClientRect: () => ({
      left: buttonData.x,
      top: buttonData.y,
      width: buttonData.width,
      height: buttonData.height,
      right: buttonData.x + buttonData.width,
      bottom: buttonData.y + buttonData.height,
    }),
  } as HTMLElement

  onShowReplyCard(virtualButton, element)
}) as EventListener)

// Listen for compose card events from page injection
document.addEventListener('nativemind:show-compose-card', ((event: CustomEvent) => {
  const { buttonData } = event.detail

  const element = buttonData.el as HTMLElement

  // Create a virtual element with the button position data
  const virtualButton = {
    getBoundingClientRect: () => ({
      left: buttonData.x,
      top: buttonData.y,
      width: buttonData.width,
      height: buttonData.height,
      right: buttonData.x + buttonData.width,
      bottom: buttonData.y + buttonData.height,
    }),
  } as HTMLElement

  onShowComposeCard(virtualButton, element)
}) as EventListener)

onMounted(async () => {
  styleSheet.value = await loadContentScriptStyleSheet(import.meta.env.ENTRYPOINT)
})

watchEffect((onCleanup) => {
  const shadowRoot = (shadowRootRef.value as { shadow_root?: ShadowRoot } | undefined)?.shadow_root
  if (shadowRoot && styleSheet.value) {
    const remove = injectStyleSheetToDocument(shadowRoot, styleSheet.value)
    onCleanup(() => {
      remove()
      logger.debug('Style sheet removed from shadow root')
    })
  }
})
</script>
